package com.haochang.chunkvod.view.vod.timepicker;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Paint.Style;
import android.support.v4.view.GestureDetectorCompat;
import android.util.AttributeSet;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
import android.widget.Scroller;

import com.haochang.chunkvod.R;

/**
 * 滚动选择器,带惯性滑动
 *
 * @author Yobert Jomi
 *         className ScrollPickerView
 *         created at  2016/10/21  18:59
 */
public class ScrollPickerView extends View
{
	private int minTextSize = 12; // 最小的字体
	private int maxTextSize = 32; // 最大的字体
	private int gravity = 0; // 字体绘制的位置  0居中，-1 居左，1居右
	// 字体渐变颜色
	private int startColor = Color.GRAY; // 从中间往外扩散item的颜色的初始值
	private int endColor = Color.parseColor("#dddddd"); // 上下两边的颜色
	private int centerColor = Color.BLACK; // 中间选中item的颜色
	private int visibleItemCount = 5; // 可见的item数量

	private boolean isInertiaScroll = true; // 快速滑动时是否惯性滚动一段距离，默认开启
	private boolean isCirculation = true; // 是否循环滚动，默认开启

	/*
	  不允许父组件拦截触摸事件，设置为true为不允许拦截，此时该设置才生效
	  当嵌入到ScrollView等滚动组件中，为了使该自定义滚动选择器可以正常工作，应设置为true
	 */
	private boolean disallowInterceptTouch = false;

	private Paint paint;
	private int measureWidth;
	private int measureHeight;
	private int mSelected; // 当前选中的item下标
	private List<String> mData = new ArrayList<String>();
	private int itemHeight = 0; // 每个条目的高度=mMeasureHeight／mVisibleItemCount
	private int mCenterY; // 中间item的起始坐标y
	private float mLastMoveY; // 触摸的坐标y

	private float moveLength = 0; // item移动长度，负数表示向上移动，正数表示向下移动

	private GestureDetectorCompat mGestureDetector;
	private OnSelectedListener mListener;

	private Scroller mScroller;
	private boolean isFling; // 是否正在惯性滑动
	private boolean isMovingCenter; // 是否正在滑向中间
	// 可以把scroller看做模拟的触屏滑动操作，mLastScrollY为上次触屏滑动的坐标
	private int mLastScrollY = 0; // Scroller的坐标y

	public ScrollPickerView(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}

	public ScrollPickerView(Context context, AttributeSet attrs, int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setStyle(Style.FILL);
		paint.setColor(Color.BLACK);
		mGestureDetector = new GestureDetectorCompat(getContext(), new FlingOnGestureListener());
		mScroller = new Scroller(getContext());

		setDataList(new ArrayList<String>(Arrays.asList("one", "two", "three", "four", "five", "six", "seven")));
		init(attrs);
	}

	private void init(AttributeSet attrs)
	{
		if (attrs != null)
		{
			TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ScrollPickerView);
			minTextSize = typedArray.getDimensionPixelSize(R.styleable.ScrollPickerView_min_text_size, minTextSize);
			maxTextSize = typedArray.getDimensionPixelSize(R.styleable.ScrollPickerView_max_text_size, maxTextSize);
			startColor = typedArray.getColor(R.styleable.ScrollPickerView_start_gradient_color, startColor);
			endColor = typedArray.getColor(R.styleable.ScrollPickerView_end_gradient_color, endColor);
			centerColor = typedArray.getColor(R.styleable.ScrollPickerView_center_color, centerColor);
			visibleItemCount = typedArray.getInt(R.styleable.ScrollPickerView_visible_item_count, visibleItemCount);
			isCirculation = typedArray.getBoolean(R.styleable.ScrollPickerView_is_circulation, isCirculation);
			disallowInterceptTouch = typedArray.getBoolean(R.styleable.ScrollPickerView_disallow_intercept_touch, disallowInterceptTouch);
			gravity = typedArray.getInt(R.styleable.ScrollPickerView_text_gravity, 0);
			typedArray.recycle();
		}
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		// 中间item
		drawItem(canvas, mSelected, 0);
		int length = visibleItemCount / 2 + 1;
		int positon;
		// 上下两边
		for (int i = 1; i <= length && i <= mData.size() / 2; i++)
		{

			// 上面的items
			positon = mSelected - i < 0 ? mData.size() + mSelected - i : mSelected - i;
			if (isCirculation)
			{//循环滚动
				drawItem(canvas, positon, -i);
			} else if (mSelected - i >= 0)
			{ // 非循环滚动
				drawItem(canvas, positon, -i);
			}

			// 下面的items
			positon = mSelected + i >= mData.size() ? mSelected + i - mData.size() : mSelected + i;
			if (isCirculation)
			{//循环滚动
				drawItem(canvas, positon, i);
			} else if (mSelected + i < mData.size())
			{ // 非循环滚动
				drawItem(canvas, positon, i);
			}
		}
	}

	/**
	 * @param canvas   画布
	 * @param position 在mData数据集中的位置
	 * @param relative 相对中间item的位置　postion-mSelected
	 */
	private void drawItem(Canvas canvas, int position, int relative)
	{
		canvas.save();
		String text = mData.get(position);
		float x;
		//relative>0 下面部分的item   relative<0 上面部分的item
		// moveLength < 0  向上滑动 减小字体  moveLength > 0 向下滑动 字体增大
		int count = ((visibleItemCount - 1) / 2);
		int initTextSize = maxTextSize - (maxTextSize - minTextSize) * Math.abs(relative) / count;
		int deltaChange = (int) ((maxTextSize - minTextSize) * moveLength / itemHeight / count);
		paint.setTextSize(initTextSize + (relative < 0 ? deltaChange : (relative == 0 ? -Math.abs(deltaChange) : -deltaChange)));

		x = gravity == 0 ? (measureWidth - paint.measureText(text)) / 2 : (gravity == -1) ? 0 : (measureWidth - paint.measureText(text));

		FontMetricsInt fmi = paint.getFontMetricsInt();
		// 绘制文字时，文字的baseline是对齐ｙ坐标的，下面换算使其垂直居中。fmi.top值是相对baseline的，为负值
		float y = mCenterY + relative * itemHeight + itemHeight / 2 - fmi.descent + (fmi.bottom - fmi.top) / 2;
		computeColor(relative);
		canvas.drawText(text,x, y + moveLength, paint);
		canvas.restore();
	}

	/**
	 * 计算字体颜色，渐变
	 *
	 * @param relative 　相对中间item的位置
	 */
	private void computeColor(int relative)
	{
		//relative>0 下面部分的item   relative<0 上面部分的item
		// moveLength < 0  向上滑动 减小字体  moveLength > 0 向下滑动 字体增大
		int count = ((visibleItemCount - 1) / 2);
		if (count >= 2)
		{
			/*
			* 以下是渐变色依赖中心颜色
			* */
			//		float rate = Math.abs(relative) / (float) count
			//				+ (relative == 0 ? Math.abs(moveLength) / itemHeight : (relative < 0 ? -moveLength / itemHeight : moveLength / itemHeight)) / count;
			//		paint.setColor(ColorUtil.getInstance().computeGradientColor(startColor,endColor, rate));

			/*
			* 以下是渐变色不依赖中心颜色
			* */
			float rateCenter = Math.abs(moveLength) / itemHeight;
			float rateGradient = Math.abs(relative) - 1 / (float) (count) + (relative < 0 ? -moveLength / itemHeight : moveLength / itemHeight) / (count - 1);
			if (relative == 0)
				paint.setColor(ColorUtil.getInstance().computeGradientColor(centerColor, startColor, rateCenter));
			else
				paint.setColor(ColorUtil.getInstance().computeGradientColor(startColor, endColor, rateGradient));
		} else if (count == 1)
		{
			float rate = Math.abs(relative) / (float) count
					+ (relative == 0 ? Math.abs(moveLength) / itemHeight : (relative < 0 ? -moveLength / itemHeight : moveLength / itemHeight)) / count;
			paint.setColor(ColorUtil.getInstance().computeGradientColor(startColor, endColor, rate));
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
	{
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		measureWidth = getMeasuredWidth();
		measureHeight = getMeasuredHeight();
		itemHeight = measureHeight / visibleItemCount;
		mCenterY = visibleItemCount / 2 * itemHeight;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event)
	{
		mGestureDetector.onTouchEvent(event);
		switch (event.getActionMasked())
		{
		case MotionEvent.ACTION_DOWN:
			if (disallowInterceptTouch)
			{ // 不允许父组件拦截事件
				ViewParent parent = getParent();
				if (parent != null)
				{
					parent.requestDisallowInterceptTouchEvent(true);
				}
			}
			// 点击时取消所有滚动效果
			cancelScroll();
			mLastMoveY = event.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			if (Math.abs(event.getY() - mLastMoveY) < 0.1f)
			{
				return true;
			}
			moveLength += event.getY() - mLastMoveY;
			mLastMoveY = event.getY();
			checkCirculation();
			invalidate();
			break;
		case MotionEvent.ACTION_UP:
			mLastMoveY = event.getY();
			moveToCenter();
			break;
		}
		return true;
	}

	@Override
	public void computeScroll()
	{
		if (mScroller.computeScrollOffset())
		{ // 正在滚动
				// 可以把scroller看做模拟的触屏滑动操作，mLastScrollY为上次滑动的坐标
			moveLength = moveLength + mScroller.getCurrY() - mLastScrollY;
			mLastScrollY = mScroller.getCurrY();
			checkCirculation();
			invalidate();
		} else
		{ // 滚动完毕
			if (isFling)
			{
				isFling = false;
				moveToCenter();
			} else if (isMovingCenter)
			{
				isMovingCenter = false;
				finishSelected();
			}
		}
	}

	public void cancelScroll()
	{
		isFling = isMovingCenter = false;
		mScroller.abortAnimation();
	}

	// 循环滚动
	private void checkCirculation()
	{
		if (moveLength >= itemHeight)
		{ // 向下滑动,最后一个元素放在头部
			mSelected--;
			if (mSelected < 0)
			{ // 滚动顶部，判断是否循环滚动
				if (isCirculation)
				{
					mSelected = mData.size() - 1;
					moveLength = 0;
				} else
				{ // 非循环滚动
					mSelected = 0;
					moveLength = itemHeight;
					if (isFling)
					{ // 停止惯性滑动，根据computeScroll()中的逻辑，下一步将调用moveToCenter()
						mScroller.forceFinished(true);
					}
					if (isMovingCenter)
					{ //  移回中间位置
						scroll(moveLength, 0);
					}
				}
			} else
			{
				moveLength = 0;
			}

		} else if (moveLength <= -itemHeight)
		{ // 向上滑动，第一个元素放在尾部
			mSelected++;
			if (mSelected >= mData.size())
			{ // 滚动末尾，判断是否循环滚动
				if (isCirculation)
				{
					mSelected = 0;
					moveLength = 0;
				} else
				{ // 非循环滚动
					mSelected = mData.size() - 1;
					moveLength = -itemHeight;
					if (isFling)
					{ // 停止惯性滑动，根据computeScroll()中的逻辑，下一步将调用moveToCenter()
						mScroller.forceFinished(true);
					}
					if (isMovingCenter)
					{ //  移回中间位置
						scroll(moveLength, 0);
					}
				}
			} else
			{
				moveLength = 0;
			}
		}
	}

	// 移动到中间位置
	private void moveToCenter()
	{

		if (!mScroller.isFinished() || isFling)
		{
			return;
		}
		cancelScroll();

		// 向下滑动
		if (moveLength > 0)
		{
			if (moveLength < itemHeight / 2)
			{
				scroll(moveLength, 0);
			} else
			{
				scroll(moveLength, itemHeight);
			}
		} else
		{
			if (-moveLength < itemHeight / 2)
			{
				scroll(moveLength, 0);
			} else
			{
				scroll(moveLength, -itemHeight);
			}
		}
	}

	// 平滑滚动
	private void scroll(float from, int to)
	{

		mLastScrollY = (int) from;
		isMovingCenter = true;
		mScroller.startScroll(0, (int) from, 0, 0);
		mScroller.setFinalY(to);
		invalidate();
	}

	/**
	 * 惯性滑动
	 */
	private void fling(float from, float vY)
	{
		mLastScrollY = (int) from;
		isFling = true;
		// 最多可以惯性滑动10个item
		mScroller.fling(0, (int) from, 0, (int) vY, 0, 0, -10 * itemHeight, 10 * itemHeight);
		invalidate();
	}

	/**
	 * 选择结束
	 */
	private void finishSelected()
	{
		if (mListener != null)
		{
			// 告诉监听器选择完毕
			post(new Runnable()
			{
				@Override
				public void run()
				{
					mListener.onSelected(mData, mSelected);
				}
			});
		}
	}

	/**
	 * 快速滑动时，惯性滑动一段距离
	 *
	 * @author huangziwei
	 */
	private class FlingOnGestureListener extends SimpleOnGestureListener
	{

		public boolean onDown(MotionEvent e)
		{
			return true;
		}

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, final float velocityY)
		{
			// 惯性滑动
			if (isInertiaScroll)
			{
				cancelScroll();
				fling(moveLength, velocityY);
			}
			return true;
		}
	}

	public List<String> getData()
	{
		return mData;
	}

	/**
	 * 设置数据源
	 * @param data 数据list
	 */
	public void setDataList(List<String> data)
	{
		if (null != data)
		{
			mData.clear();
			mData.addAll(data);
		}
		mSelected = null == data ? 0 : data.size() / 2;
		invalidate();
	}

	/**
	 * @param startColor 正中间的颜色
	 * @param endColor   上下两边的颜色
	 */
	public void setColor(int startColor, int endColor)
	{
		this.startColor = startColor;
		this.endColor = endColor;
		invalidate();
	}

	public void setMinTextSize(int size)
	{
		minTextSize = size;
		invalidate();
	}

	public void setMaxTextSize(int size)
	{
		maxTextSize = size;
		invalidate();
	}

	public String getSelectedItem()
	{
		return mData.get(mSelected);
	}

	public void setSelectedPosition(int position)
	{
		if (position < 0 || position > mData.size() - 1 || position == mSelected)
			return;
		mSelected = position;
		invalidate();
		if (mListener != null)
			finishSelected();
	}

	public void setOnSelectedListener(OnSelectedListener listener)
	{
		mListener = listener;
	}

	public OnSelectedListener getListener()
	{
		return mListener;
	}

	/**
	 * 是否惯性滚动
	 *
	 * @return 是否惯性滚动
	 */
	public boolean isInertiaScroll()
	{
		return isInertiaScroll;
	}

	/**
	 * 设置惯性滚动
	 *
	 * @param inertiaScroll inertiaScroll
	 */
	public void setInertiaScroll(boolean inertiaScroll)
	{
		this.isInertiaScroll = inertiaScroll;
	}

	/**
	 * 获取是否首尾循环
	 *
	 * @return isCirculation
	 */
	public boolean isIsCirculation()
	{
		return isCirculation;
	}

	/**
	 * 设置是否首尾循环
	 *
	 * @param isCirculation 是否循环
	 */
	public void setIsCirculation(boolean isCirculation)
	{
		this.isCirculation = isCirculation;
	}

	/**
	 * 选择回调接口
	 */
	public interface OnSelectedListener
	{
		void onSelected(List<String> data, int position);
	}

}